#include "ntlauncher.h"
#include "funcmgr.h"
#include "custombox.h"
#include "instancetcpserproc.h"
#include "worldtcpsrtproc.h"
#include <QtCore>

#include "qzipreader_p.h"

NtLauncher::NtLauncher(QWidget *parent)
    : QMainWindow(parent)
    , MPressFlag(false)
    , SerIp(ServerIpNet)
    , SerPort(10086)
    , NowRecvOn(0)
    , OnSecs(0)
    , StrSpeed(QSNULL)
    , DowCount(0)
    , TimerIndex(0)
    , InitQuality(Height)
    , LanKick(false)
{
    ui.setupUi(this);

    curPix = 1;
    m_timer = new QTimer(this);
    m_timer->setInterval(5000);
    m_timer->start();
    sFunc->ClearConfigList();
    sFunc->FormInCenter(this);
    //无边框样式
    setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint);
    //设置窗口背景透明
    setAttribute(Qt::WA_TranslucentBackground);
    //设置标题
    setWindowTitle(AppName);


    QObject::connect(ui.LauMinButton, SIGNAL(clicked()), this, SLOT(OnButtonMinClicked()));
    QObject::connect(ui.LauClsButton, SIGNAL(clicked()), this, SLOT(OnButtonCloseClicked()));


    QObject::connect(ui.FunctionButton, SIGNAL(clicked()), this, SLOT(OnFunctionClicked()));
    QObject::connect(ui.OtherButton, SIGNAL(clicked()), this, SLOT(OnOtherClicked()));
    QObject::connect(ui.PlayButton, SIGNAL(clicked()), this, SLOT(OnPlayClicked()));

    //托盘
    TrayIcon = new QSystemTrayIcon(this);
    QIcon sTrayIcon(":/Resources/Title.png");
    TrayIcon->setIcon(sTrayIcon);
    TrayIcon->setToolTip(AppName);
    TrayIcon->show();

    QObject::connect(TrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(SystemTrayIconClicked(QSystemTrayIcon::ActivationReason)));

    QMenu* TrayMenu = new QMenu(this);
    QAction* ShowAct = new QAction(QStringLiteral("显示窗口"), this);
    QAction* Exit = new QAction(QStringLiteral("退出程序"), this);
    TrayMenu->addAction(ShowAct);
    TrayMenu->addAction(Exit);
    TrayIcon->setContextMenu(TrayMenu);

    QObject::connect(ShowAct, SIGNAL(triggered()), this, SLOT(ShowWindowAction()));
    QObject::connect(Exit, SIGNAL(triggered()), this, SLOT(ExitAction()));

    ui.ImgBar->setVisible(false);
    DoEnabled(false);

    AsDataBuff.clear();
    PacketTcpClient = new QTcpSocket();
    PacketTcpClient->setSocketOption(QAbstractSocket::SocketOption::LowDelayOption, 1);
    PacketTcpClient->setProxy(QNetworkProxy::NoProxy);

    QObject::connect(PacketTcpClient, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(OnTcpError(QAbstractSocket::SocketError)));
    QObject::connect(PacketTcpClient, SIGNAL(disconnected()), this, SLOT(OnTcpClose()));
    QObject::connect(PacketTcpClient, SIGNAL(connected()), this, SLOT(OnTcpConnect()));
    QObject::connect(PacketTcpClient, SIGNAL(readyRead()), this, SLOT(OnTcpReceive()));

    WObject = new WorkObject();
    WorkThread = new QThread();
    WObject->moveToThread(WorkThread);
    QObject::connect(WorkThread, SIGNAL(started()), WObject, SLOT(WorkStart()));
    QObject::connect(WObject, SIGNAL(EmitCheckMd5Yes()), this, SLOT(AcceptCheckMd5Yes()));
    QObject::connect(WObject, SIGNAL(EmitNotOpenFile()), this, SLOT(AcceptNotOpenFile()));
    QObject::connect(WObject, SIGNAL(EmitBeginHttpTimer()), this, SLOT(AcceptBeginHttpTimer()));
    QObject::connect(WObject, SIGNAL(EmitWorkError(QNetworkReply::NetworkError)), this, SLOT(AcceptHttpError(QNetworkReply::NetworkError)));
    QObject::connect(WObject, SIGNAL(EmitWorkProgress(qint64, qint64)), this, SLOT(AcceptHttpProgress(qint64, qint64)));
    QObject::connect(WObject, SIGNAL(EmitWorkFinished()), this, SLOT(AcceptHttpDowloadFinished()));

    GForm = new GameForm();
    MForm = new ManageForm();
    QObject::connect(MForm, SIGNAL(EmitFuncSendTcpData(QString)), this, SLOT(FuncSendTcpData(QString)));

    ThreadInit = new InitThread();
    QObject::connect(ThreadInit, SIGNAL(SendMainConfig(QString, quint16)), this, SLOT(AcceptMainConfig(QString, quint16)));
    QObject::connect(ThreadInit, SIGNAL(finished()), this, SLOT(quit()));
    ThreadInit->start();

    QObject::connect(ui.Btn1, SIGNAL(clicked()), this, SLOT(OnBtn1Clicked()));
    QObject::connect(ui.Btn2, SIGNAL(clicked()), this, SLOT(OnBtn2Clicked()));
    QObject::connect(ui.Btn3, SIGNAL(clicked()), this, SLOT(OnBtn3Clicked()));
    QObject::connect(ui.Btn4, SIGNAL(clicked()), this, SLOT(OnBtn4Clicked()));
    QObject::connect(this->m_timer,SIGNAL(timeout()),this,SLOT(on_timer_out()));

    ui.Btn1->installEventFilter(this);
    ui.Btn2->installEventFilter(this);
    ui.Btn3->installEventFilter(this);
    ui.Btn4->installEventFilter(this);
}

NtLauncher::~NtLauncher()
{

}

void NtLauncher::timerEvent(QTimerEvent * event)
{
    if (event->timerId() == ResetPackTimerId)
    {
        if (PacketTcpClient->state() != QAbstractSocket::ConnectedState && PacketTcpClient->state() != QAbstractSocket::ConnectingState && !LanKick)
        {
            DoStartClient(SerIp, SerPort);
            TimerIndex++;
            if (TimerIndex > MaxIndex)
            {
                ui.LoadingLab->setText(QStringLiteral(""));
                sFunc->MBoxShow(QStringLiteral("多次尝试连接服务器失败\n无法继续使用服务\n请稍候重新启动"));
                qApp->exit(0);
                return;
            }

            ui.LoadingLab->setText(QStringLiteral("正在连接服务器中......请稍候...... 尝试次数 [ %1 ]").arg(QString::number(TimerIndex)));
        }
    }
    else if (event->timerId() == KeepAliveTimerId)
    {
        DoSendKeepBytes();
    }
    else if (event->timerId() == HttpTimerId)
    {
        OnSecs++;
        double Speed = NowRecvOn * 1.0f / OnSecs;
        StrSpeed = sFunc->AutoSize(Speed);
    }
}

void NtLauncher::DoEnabled(bool Enabled)
{
    ui.FunctionButton->setEnabled(Enabled);
    ui.OtherButton->setEnabled(Enabled);
    ui.PlayButton->setEnabled(Enabled);
    ui.NewsTextEdit->setVisible(Enabled);

    if (Enabled)
        ui.LoadingLab->setText(QStringLiteral("服务器连接成功 祝您游戏愉快"));
}

void NtLauncher::OnButtonMinClicked()
{
    MinWindowAction();
}

void NtLauncher::MinWindowAction()
{
    this->hide();
    this->setWindowState(Qt::WindowNoState);
}

void NtLauncher::OnButtonCloseClicked()
{
    close();
}

void NtLauncher::SystemTrayIconClicked(QSystemTrayIcon::ActivationReason Activation)
{
    switch (Activation)
    {
    case QSystemTrayIcon::Trigger:
        if (this->windowState() == Qt::WindowActive)
        {
            this->hide();
            this->setWindowState(Qt::WindowNoState);
        }
        else
        {
            sFunc->DoAtTopWindow(this);
        }
        break;
    default: break;
    }
}

void NtLauncher::ShowWindowAction()
{
    sFunc->DoAtTopWindow(this);
}

void NtLauncher::ExitAction()
{
    close();
}

void NtLauncher::closeEvent(QCloseEvent *event)
{
    auto Check = sFunc->MBoxShow(QStringLiteral("关闭登陆器会断开连接并且获取不到新的游戏内容\n\n确定要这样做么?"), BUTTON_OK_AND_CANCEL);
    if (Check == ID_OK)
    {
        GForm->close();
        MForm->close();
        event->accept();
    }
    else
    {
        event->ignore();
    }
}

void NtLauncher::mousePressEvent(QMouseEvent * event)
{
    MPressFlag = true;
    BeginDrag = event->pos();
    QWidget::mousePressEvent(event);
}

void NtLauncher::mouseMoveEvent(QMouseEvent * event)
{
    if (MPressFlag)
    {
        QPoint RelaPos(QCursor::pos() - BeginDrag);
        move(RelaPos);
    }
    QWidget::mouseMoveEvent(event);
}

void NtLauncher::mouseReleaseEvent(QMouseEvent * event)
{
    MPressFlag = false;
    QWidget::mouseReleaseEvent(event);
}

void NtLauncher::OnFunctionClicked()
{
    if (!sFunc->QIsNullptr(sFunc->GetConfigValue(RegURL)))
    {
        QDesktopServices::openUrl(QUrl(sFunc->GetConfigValue(RegURL)));
        return;
    }

    MForm->close();
    MForm->ShowForm();
}

/*----------------------------------------------------------------------------------------------*/

void NtLauncher::BeginDowloadPatch()
{
    if (sFunc->GetConfigValue(NPatch) == QSNULL || sFunc->GetConfigValue(MPatch) == QSNULL || sFunc->GetConfigValue(WPatch) == QSNULL)
    {
        NowGameStart();
        return;
    }

    BeginDowload(DowCount);
}

void NtLauncher::BeginDowload(qint8 Index)
{
    qint8 Count = sFunc->GetConfigValue(NPatch).split(Le).count();
    qint8 NowAt = Count - Index;

    QString FileName = sFunc->GetConfigValue(NPatch).split(Le).at(NowAt);

    QString Md5 = sFunc->GetConfigValue(MPatch).split(Le).at(NowAt);
    QString MpqPath = DirAppPath + "\\" + FileName;

    ui.ImgBar->SetPatchName(FileName);
    ui.ImgBar->SetFullPath(MpqPath);

    QString URL = sFunc->GetConfigValue(WPatch).split(Le).at(NowAt) + FileName;

    WObject->SetWorkInfo(URL, MpqPath, Md5);
    WorkThread->start();
}

void NtLauncher::OnOtherClicked()
{
    if (sFunc->QIsNullptr(sFunc->GetConfigValue(HomeURL)))
        return;
    QDesktopServices::openUrl(QUrl(sFunc->GetConfigValue(HomeURL)));
}

void NtLauncher::OnPlayClicked()
{
    BeginDowloadPatch();
}

void NtLauncher::AcceptMainConfig(QString Ip, quint16 Port)
{
    SerIp = Ip;
    SerPort = Port;
    DoStartClient(SerIp, SerPort);
    ResetPackTimerId = startTimer(1000);
}

void NtLauncher::DoHttpFinishedOrError()
{
    WorkThread->quit();
    WorkThread->wait();
    ui.ImgBar->setValue(0);
    ui.ImgBar->setVisible(false);
    killTimer(HttpTimerId);
    NowRecvOn = 0;
    OnSecs = 0;
    StrSpeed = QSNULL;
    ui.BarLab->setText("");
    ui.PlayButton->setText(QStringLiteral("进入游戏"));
}

#pragma region 下载过程错误提示
void NtLauncher::AcceptHttpError(QNetworkReply::NetworkError Error)
{
    DoHttpFinishedOrError();

    QString TextErrCode = QStringLiteral("未知错误");
    switch (Error)
    {
    case QNetworkReply::NetworkError::ConnectionRefusedError:
        TextErrCode = QStringLiteral("网址没有开启 URL错误");
        break;
    case QNetworkReply::NetworkError::RemoteHostClosedError:
        TextErrCode = QStringLiteral("网址关闭了连接");
        break;
    case QNetworkReply::NetworkError::HostNotFoundError:
        TextErrCode = QStringLiteral("找不到网址");
        break;
    case QNetworkReply::NetworkError::TimeoutError:
        TextErrCode = QStringLiteral("网络严重超时");
        break;
    case QNetworkReply::NetworkError::OperationCanceledError:
        TextErrCode = QStringLiteral("网络操作错误 被取消");
        break;
    case QNetworkReply::NetworkError::SslHandshakeFailedError:
        TextErrCode = QStringLiteral("SSL或TLS失败");
        break;
    case QNetworkReply::NetworkError::TemporaryNetworkFailureError:
        TextErrCode = QStringLiteral("临时网络故障错误");
        break;
    case QNetworkReply::NetworkError::NetworkSessionFailedError:
        TextErrCode = QStringLiteral("网络会话失败");
        break;
    case QNetworkReply::NetworkError::BackgroundRequestNotAllowedError:
        TextErrCode = QStringLiteral("网址后台请求不允许");
        break;
    case QNetworkReply::NetworkError::TooManyRedirectsError:
        TextErrCode = QStringLiteral("TooMany重定向错误");
        break;
    case QNetworkReply::NetworkError::InsecureRedirectError:
        TextErrCode = QStringLiteral("不安全重定向");
        break;
    case QNetworkReply::NetworkError::UnknownNetworkError:
        TextErrCode = QStringLiteral("未知网络错误");
        break;
    case QNetworkReply::NetworkError::ProxyConnectionRefusedError:
        TextErrCode = QStringLiteral("代理连接被拒绝");
        break;
    case QNetworkReply::NetworkError::ProxyConnectionClosedError:
        TextErrCode = QStringLiteral("与代理服务器的连接意外关闭");
        break;
    case QNetworkReply::NetworkError::ProxyNotFoundError:
        TextErrCode = QStringLiteral("找不到代理地址");
        break;
    case QNetworkReply::NetworkError::ProxyTimeoutError:
        TextErrCode = QStringLiteral("与代理服务器的连接超时或停止响应");
        break;
    case QNetworkReply::NetworkError::ProxyAuthenticationRequiredError:
        TextErrCode = QStringLiteral("代理身份验证错误");
        break;
    case QNetworkReply::NetworkError::UnknownProxyError:
        TextErrCode = QStringLiteral("未知代理错误");
        break;
    case QNetworkReply::NetworkError::ContentAccessDenied:
        TextErrCode = QStringLiteral("内容访问被拒绝");
        break;
    case QNetworkReply::NetworkError::ContentOperationNotPermittedError:
        TextErrCode = QStringLiteral("内容不允许操作");
        break;
    case QNetworkReply::NetworkError::ContentNotFoundError:
        TextErrCode = QStringLiteral("内容未找到");
        break;
    case QNetworkReply::NetworkError::AuthenticationRequiredError:
        TextErrCode = QStringLiteral("需要身份验证");
        break;
    case QNetworkReply::NetworkError::ContentReSendError:
        TextErrCode = QStringLiteral("内容发布错误");
        break;
    case QNetworkReply::NetworkError::ContentConflictError:
        TextErrCode = QStringLiteral("内容冲突错误");
        break;
    case QNetworkReply::NetworkError::ContentGoneError:
        TextErrCode = QStringLiteral("内容消失错误");
        break;
    case QNetworkReply::NetworkError::UnknownContentError:
        TextErrCode = QStringLiteral("未知内容错误");
        break;
    case QNetworkReply::NetworkError::ProtocolUnknownError:
        TextErrCode = QStringLiteral("未知协议错误或网址为空");
        break;
    case QNetworkReply::NetworkError::ProtocolInvalidOperationError:
        TextErrCode = QStringLiteral("协议验证操作错误");
        break;
    case QNetworkReply::NetworkError::ProtocolFailure:
        TextErrCode = QStringLiteral("协议失败");
        break;
    case QNetworkReply::NetworkError::InternalServerError:
        TextErrCode = QStringLiteral("内部服务器错误");
        break;
    case QNetworkReply::NetworkError::OperationNotImplementedError:
        TextErrCode = QStringLiteral("操作未实现错误");
        break;
    case QNetworkReply::NetworkError::ServiceUnavailableError:
        TextErrCode = QStringLiteral("服务器不可用错误");
        break;
    case QNetworkReply::NetworkError::UnknownServerError:
        TextErrCode = QStringLiteral("未知服务器错误");
        break;
    }

    sFunc->MBoxShow(QStringLiteral("下载更新补丁出错\n原因如下:\n") + TextErrCode);
}
#pragma endregion

void NtLauncher::AcceptHttpProgress(qint64 NowLen, qint64 FileLen)
{
    int NowValue = int(NowLen * 100.0f / FileLen);
    NowValue = (NowValue < 0 ? 0 : NowValue);
    ui.ImgBar->setValue(NowValue);
    QString Diff = sFunc->AutoSize((double)(FileLen - NowLen));
    NowRecvOn = NowLen;
    QString PatchName = ui.ImgBar->GetPatchName();
    ui.PlayButton->setText(QStringLiteral("正在更新补丁中"));
    ui.BarLab->setText(QStringLiteral("文件 [ %1 ] 剩余 %2 @ %3/s").arg(PatchName, Diff, StrSpeed));
}

void NtLauncher::AcceptHttpDowloadFinished()
{
    QFileInfo NFileInfo(ui.ImgBar->GetFullPath());
    if (NFileInfo.exists() && NFileInfo.isFile() && NFileInfo.suffix() == "zip")
    {
        QZipReader* MZipReader = new QZipReader(ui.ImgBar->GetFullPath());
        bool End = MZipReader->extractAll(NFileInfo.absolutePath());
        MZipReader->close();
        delete MZipReader;
        MZipReader = nullptr;
    }

    GameReadyNextPlay();
}

void NtLauncher::AcceptCheckMd5Yes()
{
    GameReadyNextPlay();
}

void NtLauncher::AcceptNotOpenFile()
{
    DoHttpFinishedOrError();
    DowCount = sFunc->GetConfigValue(NPatch).split(Le).count();
    sFunc->MBoxShow(QStringLiteral("获取到有新的补丁需要更新\n\n为了保证游戏体验\n\n请完全退出游戏重进"));
}

void NtLauncher::AcceptBeginHttpTimer()
{
    HttpTimerId = startTimer(1000);
    ui.ImgBar->setVisible(true);
    ui.PlayButton->setEnabled(false);
}

void NtLauncher::GameReadyNextPlay()
{
    DoHttpFinishedOrError();
    DowCount--;

    if (DowCount > 0)
    {
        BeginDowload(DowCount);
    }
    else
    {
        DowCount = sFunc->GetConfigValue(NPatch).split(Le).count();
        NowGameStart();
    }
}

void NtLauncher::NowGameStart()
{
    //由于下载在线程中执行 此处异步延迟是为了使用户知晓下载出错 无错误不影响
    QEventLoop Loop;
    QTimer::singleShot(24, &Loop, SLOT(quit()));
    Loop.exec();

    quint8 Ver = sFunc->GetConfigValue(GameVer).toUInt();
    if (sFunc->GetConfigValue(LauCheck) == QYes)
    {
        if (!sWorldTcpSerProc->DoStart(SerIp, sFunc->GetConfigValue(LPort).toUInt(), sFunc->GetConfigValue(TPort).toUInt()))
        {
            sFunc->MBoxShow(QStringLiteral("尝试初始化服务器连接失败!\n\n请联系管理员!"));
            return;
        }

        if (Ver == Leg)
        {
            if (!sInstanceTcpSerProc->DoStart(SerIp, sFunc->GetConfigValue(IPort).toUInt()))
            {
                sFunc->MBoxShow(QStringLiteral("尝试初始化服务器连接失败!\n\n请联系管理员!"));
                return;
            }
        }
    }

    QString DoCache = (Ver == Azeroth) ? QString("\\WDB") : QString("\\Cache");


    QString Wtf = (Ver == Azeroth || Ver == Tbc) ? (DirAppPath + "\\" + "realmlist.wtf") : (DirAppPath + PathMpq + "realmlist.wtf");

    if (Ver < Mop)
    {
        QFile WtfFile(Wtf);
        if (WtfFile.open(QIODevice::WriteOnly))
        {
            QString APort = (sFunc->GetConfigValue(AuthPort) == "3724") ? "" : (":" + sFunc->GetConfigValue(AuthPort));
            QString Connect = QString("SET realmlist %1%2").arg(SerIp, APort);
            QByteArray Bytes = Connect.toUtf8();
            WtfFile.write(Bytes);
            WtfFile.close();
        }
    }
    else if (Ver == Mop)
    {
        Wtf = DirAppPath + "\\WTF\\Config.wtf";
        //先读出每行 修改后保存 再重新写入
        QByteArray ReWList;
        QFile RFile(Wtf);
        if (RFile.open(QIODevice::ReadOnly))
        {
            bool In = false;
            QString Cport = sFunc->GetConfigValue(AuthPort);
            while (!RFile.atEnd())
            {
                QByteArray Line = RFile.readLine();
                if (Line.contains("realmList"))
                {
                    Line = QString("SET realmList %1:%2\r\n").arg(SerIp, Cport).toUtf8();
                    In = true;
                }

                ReWList.append(Line);
            }

            if (!In)
                ReWList.append(QString("SET realmList %1:%2\r\n").arg(SerIp, Cport).toUtf8());

            RFile.close();
        }

        QFile WFile(Wtf);
        if (WFile.open(QIODevice::WriteOnly))
        {
            WFile.write(ReWList);
            WFile.close();
        }
        ReWList.clear();

        sFunc->DeleteDir(DirAppPath + QString("\\Data\\Cache"));
    }
    else if (Ver == Leg)//7X \\WTF\\Config.wtf
    {
        Wtf = DirAppPath + "\\WTF\\Felsong.wtf";
        //先读出每行 修改后保存 再重新写入
        QByteArray ReWList;
        QFile RFile(Wtf);
        if (RFile.open(QIODevice::ReadOnly))
        {
            bool In = false;
            QString APort = (sFunc->GetConfigValue(AuthPort) == "1119") ? "" : (":" + sFunc->GetConfigValue(AuthPort));
            while (!RFile.atEnd())
            {
                QByteArray Line = RFile.readLine();
                if (Line.contains("portal"))
                {
                    Line = QString("SET portal \"%1%2\"\r\n").arg(SerIp, APort).toUtf8();
                    In = true;
                }

                ReWList.append(Line);
            }

            if (!In)
                ReWList.append(QString("SET portal \"%1%2\"\r\n").arg(SerIp, APort).toUtf8());

            RFile.close();
        }

        QFile WFile(Wtf);
        if (WFile.open(QIODevice::WriteOnly))
        {
            WFile.write(ReWList);
            WFile.close();
        }
        ReWList.clear();
    }

    sFunc->DeleteDir(DirAppPath + DoCache);

    if (Ver == Wlk && sFunc->GetConfigValue(OnClear) == QYes && !sFunc->QIsNullptr(sFunc->GetConfigValue(WMPQS)))
        sFunc->AutoDeleteFindFiles(DirAppPath + PathData);

    QEventLoop AtLoop;
    QTimer::singleShot(128, &AtLoop, SLOT(quit()));
    AtLoop.exec();

    //QFile::setPermissions(DirAppPath + "\\" + WowDName, QFileDevice::ReadOwner | QFileDevice::WriteOwner);
    bool Started = QProcess::startDetached(DirAppPath + "\\" + WowDName);
    if (!Started)
    {
        Started = sFunc->StartWorkCmd(DirAppPath + "\\" + WowDName);
        if (!Started)
        {
            ui.PlayButton->setEnabled(true);
            sFunc->MBoxShow(QStringLiteral("启动游戏进程失败 请联系管理员协助"));
            return;
        }
    }

    ui.PlayButton->setEnabled(true);

    GForm->close();
    GForm->NowShow(QStringLiteral("游戏正在启动中............\n\n云反外挂检测机制已经加载完成\n全方面查杀一切针对游戏的外挂\n请文明游戏 珍惜账号\n祝您游戏愉快!"));

    MinWindowAction();
}

/*---------------------------------------------------------------------------------------------------*/

void NtLauncher::FuncSendTcpData(QString Data)
{
    DoSendDatas(Data);
}

#pragma region Socket错误 可以忽略
void NtLauncher::OnTcpError(QAbstractSocket::SocketError ErrorCode)
{
    QString TextErrCode = QStringLiteral("未知错误");
    switch (ErrorCode)
    {
    case QAbstractSocket::SocketError::ConnectionRefusedError:
        TextErrCode = QStringLiteral("连接被对端拒绝或超时 对端没有开启");
        break;
    case QAbstractSocket::SocketError::RemoteHostClosedError:
        TextErrCode = QStringLiteral("对端关闭了连接");
        break;
    case QAbstractSocket::SocketError::HostNotFoundError:
        TextErrCode = QStringLiteral("找不到对端地址");
        break;
    case QAbstractSocket::SocketError::SocketAccessError:
        TextErrCode = QStringLiteral("操作失败 权限不足");
        break;
    case QAbstractSocket::SocketError::SocketResourceError:
        TextErrCode = QStringLiteral("由于建立了太多连接 本地网络资源不足");
        break;
    case QAbstractSocket::SocketError::SocketTimeoutError:
        TextErrCode = QStringLiteral("网络操作超时");
        break;
    case QAbstractSocket::SocketError::DatagramTooLargeError:
        TextErrCode = QStringLiteral("通信数据大于操作系统限制");
        break;
    case QAbstractSocket::SocketError::NetworkError:
        TextErrCode = QStringLiteral("网络发生错误 网线断开");
        break;
    case QAbstractSocket::SocketError::AddressInUseError:
        TextErrCode = QStringLiteral("指定的对端地址已在使用中");
        break;
    case QAbstractSocket::SocketError::SocketAddressNotAvailableError:
        TextErrCode = QStringLiteral("指定的对端地址不属于主机");
        break;
    case QAbstractSocket::SocketError::UnsupportedSocketOperationError:
        TextErrCode = QStringLiteral("操作系统不支持网络类型 IPV4或IPV6");
        break;
    case QAbstractSocket::SocketError::UnfinishedSocketOperationError:
        TextErrCode = QStringLiteral("尝试的操作尚未完成");
        break;
    case QAbstractSocket::SocketError::ProxyAuthenticationRequiredError:
        TextErrCode = QStringLiteral("使用代理需要身份验证");
        break;
    case QAbstractSocket::SocketError::SslHandshakeFailedError:
        TextErrCode = QStringLiteral("SSL或TLS失败");
        break;
    case QAbstractSocket::SocketError::ProxyConnectionRefusedError:
        TextErrCode = QStringLiteral("无法连接代理服务器");
        break;
    case QAbstractSocket::SocketError::ProxyConnectionClosedError:
        TextErrCode = QStringLiteral("与代理服务器的连接意外关闭");
        break;
    case QAbstractSocket::SocketError::ProxyConnectionTimeoutError:
        TextErrCode = QStringLiteral("与代理服务器的连接超时或停止响应");
        break;
    case QAbstractSocket::SocketError::ProxyNotFoundError:
        TextErrCode = QStringLiteral("找不到代理地址");
        break;
    case QAbstractSocket::SocketError::ProxyProtocolError:
        TextErrCode = QStringLiteral("无法响应代理服务器");
        break;
    case QAbstractSocket::SocketError::OperationError:
        TextErrCode = QStringLiteral("网络操作错误");
        break;
    case QAbstractSocket::SocketError::SslInternalError:
        TextErrCode = QStringLiteral("SSL内部错误");
        break;
    case QAbstractSocket::SocketError::SslInvalidUserDataError:
        TextErrCode = QStringLiteral("SSL无效数据错误");
        break;
    case QAbstractSocket::SocketError::TemporaryError:
        TextErrCode = QStringLiteral("暂时性错误");
        break;
    case QAbstractSocket::SocketError::UnknownSocketError:
        TextErrCode = QStringLiteral("未知错误");
        break;
    }
}
#pragma endregion

void NtLauncher::OnTcpClose()
{
    DoEnabled(false);
}

void NtLauncher::DoStartClient(QString NetIp, quint16 Port)
{
    ui.LoadingLab->setText(QStringLiteral("正在连接服务器中......请稍候...... 尝试次数 [ 0 ]"));
    PacketTcpClient->abort();
    PacketTcpClient->connectToHost(QHostAddress(NetIp), Port);
}

QByteArray NtLauncher::BuilderPack(QByteArray SourceByte)
{
    quint32 Len = SourceByte.size();
    QByteArray IntBytes = sFunc->IntToBytes(Len);
    QByteArray SnedBytes = IntBytes.append(SourceByte);
    return SnedBytes;
}

void NtLauncher::DoSendDatas(QString Datas)
{
    if (PacketTcpClient->state() != QAbstractSocket::ConnectedState)
        return;

    if (Datas == QSNULL)
        return;

    QByteArray SourceByte = Datas.toUtf8();
    DoSendBytes(SourceByte);
}

void NtLauncher::DoSendKeepBytes()
{
    if (PacketTcpClient->state() != QAbstractSocket::ConnectedState)
        return;

    QByteArray Bytes;
    Bytes.resize(4);
    Bytes[0] = 0;
    Bytes[1] = 0;
    Bytes[2] = 0;
    Bytes[3] = 0;

    PacketTcpClient->write(BuilderPack(Bytes));
}

void NtLauncher::DoSendBytes(QByteArray Bytes, bool DoKey)
{
    if (PacketTcpClient->state() != QAbstractSocket::ConnectedState)
        return;

    if (Bytes.length() <= 0)
        return;

    PacketTcpClient->write(BuilderPack(DoKey ? sFunc->EncryptForByte(Bytes) : Bytes));
}

void NtLauncher::OnTcpConnect()
{
    InitQuality = Height;
    TimerIndex = 0;
    DoEnabled(true);
    KeepAliveTimerId = startTimer(QKeepTime);

    //由于可能XP系统没有打开WMI服务 获取不到机器码 所以使用另一个方法
    QString PcKey = (QSysInfo::windowsVersion() == QSysInfo::WV_XP) ? sFunc->GetWinXpKey() : sFunc->NowPcKey();
    DoSendDatas(QString::number(AutoPcKey) + Se + PcKey + Se);
}

void NtLauncher::OnTcpReceive()
{
    if (PacketTcpClient->bytesAvailable() <= 0)
        return;

    //将所有接收到的数据包全部放入缓冲区
    AsDataBuff.append(PacketTcpClient->readAll());

    //协议是 4字节包 + 完整包 = 接收到的数据包 4字节表示32位的完整包长度
    //期待的是完整包的业务 所以必须要处理粘包拆包
    while (AsDataBuff.size() > 0)
    {
        //如果长度小于4 表示连包头都不够 则等下次接收足够再继续
        if (AsDataBuff.size() < sizeof(int))
            break;

        //得到完整包的长度 (缓冲区左边取4 然后计算完整包长度)
        qint32 BodyLen = sFunc->BytesToInt(AsDataBuff.left(sizeof(int)));
        //得到一个封装好的数据包长度
        qint32 DataLen = BodyLen + sizeof(int);
        //如果缓冲区的长度 小于 一个封装好的数据包长度 则等下次接收足够再继续
        if (AsDataBuff.size() < DataLen)
            break;

        //根据协议 把前面4字节移除 以便后续得到完整包
        AsDataBuff.remove(0, sizeof(int));
        //得到缓冲区前完整包长度的完整包 (缓冲区左边取完整包长度) 然后处理业务
        QByteArray IntactBytes = AsDataBuff.left(BodyLen);
        HandlerReceiveData(IntactBytes);

        //处理完以后再把缓冲区完整包移除掉 继续处理下一次解析
        AsDataBuff.remove(0, BodyLen);
    }
}

#pragma region 处理完整的数据
void NtLauncher::HandlerReceiveData(QByteArray IntactBytes)
{
    QByteArray NowBytes = sFunc->DecryptForByte(IntactBytes);
    QString ReadString = QString::fromUtf8(NowBytes);
    if (!ReadString.contains(Se))
        return;

    Command Head = Command(QString(ReadString.split(Se)[0]).toInt());
    switch (Head)
    {
    case AutoConfig:
    {
        QStringList ReadList = ReadString.split(Se);
        DowCount = ReadList.at(NPatch).split(Le).count();
        sFunc->AutoLoadConfigList(ReadList);
    }
    break;
    case SendMsg:
    {
        QString SendMsg = ReadString.split(Se)[1];
        sFunc->MBoxShow(SendMsg);
    }
    break;
    case KickNow:
    {
        ui.LoadingLab->setText(QStringLiteral("你已经被管理员强制断开......"));
        LanKick = true;
        sWorldTcpSerProc->DoStop();
        PacketTcpClient->close();
        sFunc->MBoxShow(QStringLiteral("你违规被强制踢出 无法游戏"));
        qApp->exit(0);
    }
    break;
    case BanPcKey:
    {
        ui.LoadingLab->setText(QStringLiteral("你已经被管理员强制断开......"));
        LanKick = true;
        sWorldTcpSerProc->DoStop();
        PacketTcpClient->close();
        QString PcKey = ReadString.split(Se)[1];

        QClipboard *Clipboard = QApplication::clipboard();
        Clipboard->setText(PcKey);

        sFunc->MBoxShow(QStringLiteral("你违规被封禁机器码 无法游戏\n") + PcKey + QStringLiteral("\n已自动复制到剪切板\nCtrl+V发给管理员可解封"));
        qApp->exit(0);
    }
    break;
    case ShowTask:
    {
        HANDLE HProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
        if (HProcess)
        {
            QString Info;
            PROCESSENTRY32 PInfo = { sizeof(PROCESSENTRY32) };

            while (Process32Next(HProcess, &PInfo))
            {
//                QString ProcName = QString::fromLocal8Bit(PInfo.szExeFile);
                QString ProcId = QString::number(PInfo.th32ProcessID);
//                Info.append(ProcName + "#" + ProcId + "^");
            }

            DoSendDatas(QString::number(ShowTask) + Se + Info + Se);
        }
    }
    break;
    case ShowScreen:
    {
        QString ScreenB64 = QString(sFunc->ScreenAutoImgToByte(InitQuality).toBase64());
        DoSendDatas(QString::number(ShowScreen) + Se + ScreenB64 + Se + QString::number(InitQuality) + Se);
    }
    break;
    case ImgQuality:
    {
        InitQuality = QualityFlags(ReadString.split(Se)[1].toInt());
    }
    break;
    case UpdateConfig:
    {
        QStringList ReadList = ReadString.split(Se);

        if (ReadList.at(MPatch) != sFunc->GetConfigValue(MPatch))
            sFunc->MBoxShow(QStringLiteral("获取到有新的补丁需要更新\n\n为了保证游戏体验\n\n请完全退出游戏重进"));

        sFunc->AutoLoadConfigList(ReadList);
    }
    break;
    case PushText:
    {
        QString GText = ReadString.split(Se)[1];
        ui.NewsTextEdit->setPlainText(GText);
    }
    break;
    case CloseReg:
    {
        sFunc->MBoxShow(QStringLiteral("暂未开放账号注册功能\n\n请联系管理员"));
    }
    break;
    case RegUserHas:
    {
        sFunc->MBoxShow(QStringLiteral("账号已存在 请重新输入"));
    }
    break;
    case RegSuccess:
    {
        QString User = ReadString.split(Se)[1];
        QString Pass = ReadString.split(Se)[2];
        MForm->SetTextComplete(QStringLiteral("账号注册成功 请务必牢记账号密码"), QStringLiteral("账号: %1 密码: %2").arg(User, Pass));
        MForm->ResetEditTextCode();
    }
    break;
    case ClosePlayer:
    {
        sFunc->MBoxShow(QStringLiteral("暂未开放角色解卡功能\n\n请联系管理员"));
    }
    break;
    case UnPlayerNot:
    {
        sFunc->MBoxShow(QStringLiteral("账号或密码不正确 请重新输入"));
    }
    break;
    case UnPlayerWrong:
    {
        sFunc->MBoxShow(QStringLiteral("角色不属于当前账号 请重新输入"));
    }
    break;
    case UnPlayerSuccess:
    {
        QString PlayerName = ReadString.split(Se)[1];
        MForm->SetTextComplete(QStringLiteral("角色解卡成功"), QStringLiteral("角色: %1").arg(PlayerName));
        MForm->ResetEditTextCode();
    }
    break;
    case ClosePass:
    {
        sFunc->MBoxShow(QStringLiteral("暂未开放更改密码功能\n\n请联系管理员"));
    }
    break;
    case PassWrong:
    {
        sFunc->MBoxShow(QStringLiteral("账号或旧密码不正确 请重新输入"));
    }
    break;
    case PassSuccess:
    {
        QString NewPass = ReadString.split(Se)[1];
        MForm->SetTextComplete(QStringLiteral("更改密码成功"), QStringLiteral("新密码: %1").arg(NewPass));
        MForm->ResetEditTextCode();
    }
    break;
    case MError:
    {
        sFunc->MBoxShow(QStringLiteral("数据库或其他非法出错 请联系管理员"));
    }
    break;
    }
}
#pragma endregion

bool NtLauncher::eventFilter(QObject *Watched, QEvent *event)
{
    if (Watched == ui.Btn1)
    {
        if (event->type() == QEvent::HoverEnter)
        {
            ui.Btn1->move(ui.Btn1->x() - 10, ui.Btn1->y() - 10);
            ui.Btn1->setFixedSize(500, 320);
            ui.Btn1->setStyleSheet("QPushButton#Btn1 { border-radius: 4px;background:transparent;background-image: url(:/Resources/01-1.png);border: 3px solid rgb(0 , 255 , 255); }");
        }
        else if (event->type() == QEvent::HoverLeave)
        {
            ui.Btn1->move(ui.Btn1->x() + 10, ui.Btn1->y() + 10);
            ui.Btn1->setFixedSize(480, 300);
            ui.Btn1->setStyleSheet("QPushButton#Btn1 { border-radius: 4px;background:transparent;background-image: url(:/Resources/01.png); }");
        }
    }
    else if (Watched == ui.Btn2)
    {
        if (event->type() == QEvent::HoverEnter)
        {
            ui.Btn2->move(ui.Btn2->x() - 10, ui.Btn2->y() - 10);
            ui.Btn2->setFixedSize(340, 200);
            ui.Btn2->setStyleSheet("QPushButton#Btn2 { border-radius: 4px;background:transparent;background-image: url(:/Resources/02-2.png);border: 3px solid rgb(0 , 255 , 255); }");
        }
        else if (event->type() == QEvent::HoverLeave)
        {
            ui.Btn2->move(ui.Btn2->x() + 10, ui.Btn2->y() + 10);
            ui.Btn2->setFixedSize(320, 180);
            ui.Btn2->setStyleSheet("QPushButton#Btn2 { border-radius: 4px;background:transparent;background-image: url(:/Resources/02.png); }");
        }
    }
    else if (Watched == ui.Btn3)
    {
        if (event->type() == QEvent::HoverEnter)
        {
            ui.Btn3->move(ui.Btn3->x() - 10, ui.Btn3->y() - 10);
            ui.Btn3->setFixedSize(340, 200);
            ui.Btn3->setStyleSheet("QPushButton#Btn3 { border-radius: 4px;background:transparent;background-image: url(:/Resources/03-3.png);border: 3px solid rgb(0 , 255 , 255); }");
        }
        else if (event->type() == QEvent::HoverLeave)
        {
            ui.Btn3->move(ui.Btn3->x() + 10, ui.Btn3->y() + 10);
            ui.Btn3->setFixedSize(320, 180);
            ui.Btn3->setStyleSheet("QPushButton#Btn3 { border-radius: 4px;background:transparent;background-image: url(:/Resources/03.png); }");
        }
    }
    else if (Watched == ui.Btn4)
    {
        if (event->type() == QEvent::HoverEnter)
        {
            ui.Btn4->move(ui.Btn4->x() - 10, ui.Btn4->y() - 10);
            ui.Btn4->setFixedSize(340, 200);
            ui.Btn4->setStyleSheet("QPushButton#Btn4 { border-radius: 4px;background:transparent;background-image: url(:/Resources/04-4.png);border: 3px solid rgb(0 , 255 , 255); }");
        }
        else if (event->type() == QEvent::HoverLeave)
        {
            ui.Btn4->move(ui.Btn4->x() + 10, ui.Btn4->y() + 10);
            ui.Btn4->setFixedSize(320, 180);
            ui.Btn4->setStyleSheet("QPushButton#Btn4 { border-radius: 4px;background:transparent;background-image: url(:/Resources/04.png); }");
        }
    }

    return QWidget::eventFilter(Watched, event);
}

void NtLauncher::OnBtn1Clicked()
{
    if (sFunc->QIsNullptr(sFunc->GetConfigValue(G1URL)))
        return;
    QDesktopServices::openUrl(QUrl(sFunc->GetConfigValue(G1URL)));
}

void NtLauncher::OnBtn2Clicked()
{
    if (sFunc->QIsNullptr(sFunc->GetConfigValue(G2URL)))
        return;
    QDesktopServices::openUrl(QUrl(sFunc->GetConfigValue(G2URL)));
}

void NtLauncher::OnBtn3Clicked()
{
    if (sFunc->QIsNullptr(sFunc->GetConfigValue(G3URL)))
        return;
    QDesktopServices::openUrl(QUrl(sFunc->GetConfigValue(G3URL)));
}

void NtLauncher::OnBtn4Clicked()
{
    if (sFunc->QIsNullptr(sFunc->GetConfigValue(G4URL)))
        return;
    QDesktopServices::openUrl(QUrl(sFunc->GetConfigValue(G4URL)));
}



void NtLauncher::on_timer_out()
{
    if(curPix == 1){
        ui.Btn1->setStyleSheet("border:none;border-radius: 4px;background:transparent; background-image: url(:/Resources/02.png);");
        ui.radioButton->setChecked(false);
        ui.radioButton_2->setChecked(true);
        ui.radioButton_3->setChecked(false);
        ui.radioButton_4->setChecked(false);
        curPix = 2;
    }else if(curPix == 2){
        ui.Btn1->setStyleSheet("border:none;border-radius: 4px;background:transparent; background-image: url(:/Resources/03.png);");
        ui.radioButton->setChecked(false);
        ui.radioButton_2->setChecked(false);
        ui.radioButton_3->setChecked(true);
        ui.radioButton_4->setChecked(false);
        curPix = 3;
    }
    else if(curPix == 3){
            ui.Btn1->setStyleSheet("border:none;border-radius: 4px;background:transparent; background-image: url(:/Resources/04.png);");
            ui.radioButton->setChecked(false);
            ui.radioButton_2->setChecked(false);
            ui.radioButton_3->setChecked(false);
            ui.radioButton_4->setChecked(true);
            curPix = 4;
        }
    else if(curPix == 4){
            ui.Btn1->setStyleSheet("border:none;border-radius: 4px;background:transparent; background-image: url(:/Resources/01.png);");
            ui.radioButton->setChecked(true);
            ui.radioButton_2->setChecked(false);
            ui.radioButton_3->setChecked(false);
            ui.radioButton_4->setChecked(false);
            curPix = 1;
        }
}


void NtLauncher::on_radioButton_clicked()
{
    curPix =1;
    ui.Btn1->setStyleSheet("border:none;border-radius: 4px;background:transparent; background-image: url(:/Resources/01.png);");
}


void NtLauncher::on_radioButton_2_clicked()
{
    curPix =2;
    ui.Btn1->setStyleSheet("border:none;border-radius: 4px;background:transparent; background-image: url(:/Resources/02.png);");
}


void NtLauncher::on_radioButton_3_clicked()
{
    curPix =3;
    ui.Btn1->setStyleSheet("border:none; background:transparent; background-image: url(:/Resources/03.png);");
}


void NtLauncher::on_radioButton_4_clicked()
{
    curPix =4;
    ui.Btn1->setStyleSheet("border:none: background:transparent; background-image: url(:/Resources/04.png);");
}

